package com.chukun.gateway.core.limiter.rule.impl;

import com.alibaba.fastjson2.JSON;
import com.chukun.gateway.common.rule.Rule;
import com.chukun.gateway.core.limiter.GuavaCountLimiter;
import com.chukun.gateway.core.limiter.RedisDistributeCountLimiter;
import com.chukun.gateway.core.limiter.rule.IGatewayFlowCtlRule;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.chukun.gateway.common.constants.GlobalFilterConst.*;

/**
 * @author chukun
 * @version 1.0.0
 * @description 流控规则，根据路径进行流控
 * @createTime 2023/12/10 22:27
 */
public class FlowControlByPathRule implements IGatewayFlowCtlRule {

    private final String serviceId;

    private final String path;

    private final RedisDistributeCountLimiter distributeCountLimiter;

    private static Map<String, FlowControlByPathRule> servicePaths = new ConcurrentHashMap<>();

    private static final String LIMIT_MESSAGE ="您的请求过于频繁,请稍后重试";

    public FlowControlByPathRule(String serviceId, String path, RedisDistributeCountLimiter distributeCountLimiter) {
        this.serviceId = serviceId;
        this.path = path;
        this.distributeCountLimiter = distributeCountLimiter;
    }

    public static  FlowControlByPathRule getInstance(String serviceId, String path){
        String key = String.format("%s.%s", serviceId, path);
        FlowControlByPathRule flowCtlByPathRule = servicePaths.get(key);
        if(flowCtlByPathRule == null){
            flowCtlByPathRule = new FlowControlByPathRule(serviceId,path, new RedisDistributeCountLimiter());
            servicePaths.put(key,flowCtlByPathRule);
        }
        return  flowCtlByPathRule;
    }


    @Override
    public void doFlowControlFilter(Rule.FlowControlConfig flowCtlConfig, String serviceId) {
        if(flowCtlConfig == null || StringUtils.isEmpty(serviceId) || StringUtils.isEmpty(flowCtlConfig.getConfig())){
            return;
        }
        Map<String,Integer> configMap = JSON.parseObject(flowCtlConfig.getConfig(),Map.class);
        if(!configMap.containsKey(FLOW_CTL_LIMIT_DURATION) || !configMap.containsKey(FLOW_CTL_LIMIT_PERMITS)){
            return;
        }
        double duration = configMap.get(FLOW_CTL_LIMIT_DURATION);
        double permits = configMap.get(FLOW_CTL_LIMIT_PERMITS);
        boolean flag = true;
        String key = String.format("%s.%s", serviceId, path);
        if(FLOW_CTL_MODEL_DISTRIBUTED.equalsIgnoreCase(flowCtlConfig.getModel())){
            flag = distributeCountLimiter.doFlowControl(key,(int)permits,(int)duration);
        }else {
            GuavaCountLimiter guavaCountLimiter = GuavaCountLimiter.getInstance(serviceId,flowCtlConfig);
            if(guavaCountLimiter == null){
                throw  new RuntimeException("获取单机限流工具类为空");
            }
            double count = Math.ceil(permits/duration);
            flag = guavaCountLimiter.acquire((int)count);
        }
        if(!flag){
            throw new RuntimeException(LIMIT_MESSAGE);
        }
    }
}
